package common

import (
	"encoding/json"
	"fmt"
	"github.com/go-xorm/xorm"
	"github.com/mjiulee/lego"
	"sync"
)

//定义4个构架体系级别：系统/租户/应用/用户
const (
	ARCH_LEVEL_SYS_0    = 0 //系统
	ARCH_LEVEL_TENANT_1 = 1 //租户
	ARCH_LEVEL_APP_2    = 2 //应用
	ARCH_LEVEL_USER_3   = 3 //用户
)

const (
	LOGIN_MODE_WECHAT = 0 //微信登录
	LOGIN_MODE_WEB    = 1 //WEB登录
	//其它的还未支持，以后可能支持支付宝小程序登录
)

const (
	STATE_NO      = 0
	STATE_YES     = 1

	STATE_APPLYING = 3 //
	STATE_INVALID = 0xff //比如，这个状态可以用于未通过审核状态，0可以表示还没有审核

)

type PAY_TO string
const (
	PAY_TO_SYS PAY_TO = "PAY_TO_SYS"
	PAY_TO_TENANT PAY_TO = "PAY_TO_TENANT"
)

const (
    MenuMode_Tenant = 1 //租户管理端菜单
	MenuMode_MiniApp = 2 //微应用管理端菜单
)


//收支类型  IncomeType
const (
	In  = 1 //收入
	Out = 2 //支出
)

//业务类型 BusinessType
const (
	Sale    = 1 //销售
	Forward = 2 //提现
)

const (
	ORDER_NULL = ""
	ORDER_ASC = "asc"
	ORDER_DESC = "desc"
)

type PageParam struct {
	Keyword string `json:"keyword"`
	Page int `json:"page" vd:"$>0"`
	Psize int `json:"psize"`
	OrderField string `json:"order_field"`
	Order string `json:"order"`
}



type Who struct {
	TenantId  int64 `xorm:"" json:"tenant_id,string"` // ["configData","show","input"]
	MiniAppId int64 `xorm:"" json:"mini_app_id,string"` // ["configData","show","input"]
	Uid       int64 `xorm:"" json:"uid,string"` // ["configData","show","input"]
}

var SYS_WHO = NewWho(0, 0, 0) //这个who值来表示系统

func NewWho(tenantId int64, miniAppId int64, uid int64) *Who {
	return &Who{
		TenantId:  tenantId,
		MiniAppId: miniAppId,
		Uid:       uid,
	}
}

//约定appWho只筛选mini_app_id和tenant_id字段
func GetDBWithFilterByTid(tid int64) *xorm.Session {
	return lego.GetDBEngine().Where("if_del = ?", 0).And("tenant_id = ?", tid)
}

func GetDBEngineWithFilterByAppWho(who *Who) *xorm.Session {
	return lego.GetDBEngine().Where("if_del = ?", 0).And("mini_app_id = ? AND tenant_id = ?", who.MiniAppId, who.TenantId)
}

func GetDBEngineWithFilterByAppId(who *Who) *xorm.Session {
	return lego.GetDBEngine().Where("if_del = ?", 0).And("mini_app_id = ?", who.MiniAppId)
}

func GetDBEngineWithFilterByMiniAppId(miniAppId int64) *xorm.Session {
	return lego.GetDBEngine().Where("if_del = ?", 0).And("mini_app_id = ?", miniAppId)
}

//TODO 后续把where改为And，因为where只能用在开头，不太灵活
func GetDBSessionWithFilterByAppWho(session *xorm.Session, appwho *Who) *xorm.Session {
	return session.Where("if_del = ?", 0).And("mini_app_id = ? And tenant_id = ?", appwho.MiniAppId, appwho.TenantId)
}

func GetDBSessionWithFilterByAppId(session *xorm.Session, appwho *Who) *xorm.Session {
	return session.Where("if_del = ?", 0).And("mini_app_id = ?", appwho.MiniAppId)
}

func GetDBSessionWithFilterByAppWhoWithTableName(session *xorm.Session, who *Who, tableName string) *xorm.Session {
	if tableName != "" {
		wherestring := fmt.Sprintf("%s.if_del = 0 And %s.mini_app_id = ? And %s.tenant_id = ?", tableName, tableName, tableName)
		return session.Where(wherestring, who.MiniAppId, who.TenantId)
	}
	return session.Where("if_del = 0 And mini_app_id = ? And tenant_id = ?", who.MiniAppId, who.TenantId)
}

func GetDBEngineWithFilterByWho(who *Who) *xorm.Session {
	return lego.GetDBEngine().Where("if_del = ?", 0).And("mini_app_id = ? AND tenant_id = ? AND uid = ?", who.MiniAppId, who.TenantId, who.Uid)
}

func GetDBEngineByTenantWho(who *Who) *xorm.Session {
	return lego.GetDBEngine().Where("if_del = ?", 0).And("tenant_id = ?", who.TenantId)
}


//
func GetDBSessionWithFilterByWho(session *xorm.Session, who *Who) *xorm.Session {
	return session.Where("if_del = ?", 0).And("mini_app_id = ? AND tenant_id = ? AND uid = ?", who.MiniAppId, who.TenantId, who.Uid)
}

func (this *Who) GetDBEngineWithFilter() *xorm.Session {
	s := GetDBEngineWithFilterByWho(this)
	return s
}


func (this *Who) GetTenantIdFilter() *xorm.Session {
	s := lego.GetDBEngine().Where("if_del = ?", 0).And("tenant_id = ?", this.TenantId)
	return s
}



func (this *Who) GetTenantId() int64 {
	return this.TenantId
}

func (this *Who) GetMiniAppId() int64 {
	return this.MiniAppId
}

func (this *Who) GetUid() int64 {
	return this.Uid
}

func (this *Who) IsNUll() bool {
	if this.MiniAppId == APP_ID_NULL && this.TenantId == APP_ID_NULL && this.Uid == APP_ID_NULL {
		return true
	}
	return false
}

func (this *Who) IsSys() bool {
	if this.MiniAppId == APP_ID_SYS /*1*/ && this.TenantId == APP_ID_NULL && this.Uid == APP_ID_NULL {
		return true
	}
	return false
}

func (this *Who) IsTenant() bool {
	if this.TenantId != APP_ID_NULL && this.MiniAppId == APP_ID_NULL && this.Uid == APP_ID_NULL {
		return true
	}
	return false
}

//是否是某个租户的APP
func (this *Who) IsMiniAppInTenant() bool {
	if this.TenantId != APP_ID_NULL && this.MiniAppId != APP_ID_NULL && this.Uid == APP_ID_NULL {
		return true
	}
	return false
}

//是app，可能是单纯的app，也可能是指某个租户的app
func (this *Who) IsMiniApp() bool {
	if /*this.TenantId == APP_ID_NULL && */ this.MiniAppId == APP_ID_NULL && this.Uid == APP_ID_NULL {
		return true
	}
	return false
}

//只是单纯的app
func (this *Who) IsMiniAppOnly() bool {
	if this.TenantId == APP_ID_NULL && this.MiniAppId == APP_ID_NULL && this.Uid == APP_ID_NULL {
		return true
	}
	return false
}

func (this *Who) IsUser() bool {
	if this.MiniAppId != APP_ID_NULL && this.TenantId != APP_ID_NULL && this.Uid != APP_ID_NULL {
		return true
	}
	return false
}

func (this *Who) ToMiniApp() Who {
	who := Who{
		TenantId:  0,
		MiniAppId: this.MiniAppId,
		Uid:       0,
	}
	return who
}

func (this *Who) ToMiniAppInTenant() Who {
	who := Who{
		TenantId:  this.TenantId,
		MiniAppId: this.MiniAppId,
		Uid:       0,
	}
	return who
}

func (this *Who) IsEqual(who2 *Who) bool {
	if this.Uid == who2.Uid &&
	   this.TenantId == who2.TenantId &&
	   this.MiniAppId == who2.MiniAppId {
		return true
	}
	return false
}

//是否是同一个租户，这里也比较了 MiniAppId
func (this *Who) IsEqualTenant(who2 *Who) bool {
	if  this.TenantId == who2.TenantId &&
		this.MiniAppId == who2.MiniAppId {
		return true
	}
	return false
}


//将who的坐标转换为字符串类型
func (this *Who) ToString() string {
	whoStr := fmt.Sprintf("who_t_%d_a_%d_u_%d", this.TenantId, this.MiniAppId, this.Uid)
	return whoStr
}

func (this *Who) ToJson() string {
	jsonByte, _ := json.Marshal(this)
	jsonStr := string(jsonByte)
	return jsonStr
}

type WhoMap struct {
	lock sync.RWMutex
	Map  map[string]interface{}
}

func NewWhoMap() *WhoMap {
	this := &WhoMap{}
	this.Map = make(map[string]interface{})
	return this
}

func (this *WhoMap) SetVal(who Who, value interface{}) {
	this.lock.Lock()
	defer this.lock.Unlock()
	this.Map[who.ToString()] = value
}

func (this *WhoMap) GetVal(who Who) interface{} {
	this.lock.RLock()
	defer this.lock.RUnlock()
	value := this.Map[who.ToString()]
	return value
}

// Returns true if k is exist in the map.

func (this *WhoMap) Check(who Who) bool {
	this.lock.RLock()
	defer this.lock.RUnlock()
	if _, ok := this.Map[who.ToString()]; !ok {
		return false
	}

	return true

}

func (this *WhoMap) Delete(who Who) {
	this.lock.Lock()
	defer this.lock.Unlock()
	delete(this.Map, who.ToString())
}

func (this *WhoMap) GetMap() map[string]interface{} {
	return this.Map
}
